#ifndef NIGHT_ARRAY_BIND
#define NIGHT_ARRAY_BIND

#include "core.hpp"
#include "shape.hpp"

namespace night {

namespace array {

template< typename E, typename R, typename S > struct bind_view<E,R,S,0> { typedef void type; };

template< typename E, typename R, typename S >
struct bind_view<E,R,S,1>
{
	typedef R type;

	static type apply ( typename E::param_type src, size_type s ) { return src.at (s); }
};

template< typename E, typename R, typename S, int dim >
struct bind_view : Expr< bind_view<E,R,S,dim>, R, typename tail<S>::type >
{
	typedef typename bind_view::result_type result_t;
	typedef typename bind_view::shape_type shape_t;
	typedef iterator<bind_view,shape_t> iterator, const_iterator;

	typename E::value_type expr;
	size_type i;

	bind_view ( typename E::param_type src, size_type s ) 
		: bind_view::base_type ( tail<S>::apply( src.shape () ) ), expr(src), i(s) {}

	bind_view & operator = ( bind_view const & rhs ) { return this->assign (rhs); }
	template< typename RE > bind_view & operator = ( RE const & rhs ) { return this->assign (rhs); }

	const_iterator begin () const { return const_iterator ( *this, 0 ); }
	const_iterator end () const { return const_iterator ( *this, this->size() ); }

	result_t at ( size_type j ) const { return this->expr.at ( this->i, j ); }
	result_t at ( size_type j, size_type k ) const { return this->expr.at ( this->i, j, k ); }

	typedef bind_view type;

	static bind_view apply ( typename E::param_type src, size_type s ) { return bind_view (src,s); }
};

} // end namespace night::array

} // end namespace night

#endif
